﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////


#include "GnufFamilyBlock.h"
#include "GnufFamilyTreeNodeUtil.h"
#include "FamilyCmdAvailibilityUtils.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "GnufInfo.h"
#include "GnufTree.h"
#include "ICategory.h"
#include "ICategoryLibrary.h"
#include "IDocument.h"
#include "IElementBasicInformation.h"
#include "IFamily.h"
#include "IFamilyType.h"
#include "IUiDocument.h"
#include "IFamilyExternalForm.h"
#include "IGenericElement.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"

using namespace gfam;
using namespace gcmp;
using namespace gnuf;

namespace
{
    bool IsCADSheet(const std::wstring& familyName)
    {
        // ends with ".dxf" ".dwg" ".sat" ?
        if (familyName.length() > 4)
        {
            std::wstring extention = familyName.substr(familyName.length() - 4);
            if (gcmp::StrICmp(extention.c_str(), L".dxf") == 0 || gcmp::StrICmp(extention.c_str(), L".dwg") == 0
                || gcmp::StrICmp(extention.c_str(), L".pdf") == 0|| gcmp::StrICmp(extention.c_str(), L".sat") == 0)
                return true;
        }

        return false;
    }
}

gnuf::TreeNode* gfam::FamilyBlock::initBlockImpl(gnuf::TreeBoard* treeBoard)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(treeBoard != nullptr, L"treeBoard is nullptr", L"paramodel", L"2024-02-20");

    TreeNode* pFamilyRoot = treeBoard->addTree();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pFamilyRoot != nullptr, L"pFamilyRoot is nullptr", L"paramodel", L"2024-02-20");

    pFamilyRoot->setInfo(0, Info(FAMILY_TEXT, FAMILY_TEXT, GnufFamilyTreeNodeUtil::GetIconPathForFamilyRootItem()));
    pFamilyRoot->setUserDataAt(Gnuf_FAMILY_USER_DATA_ROLE, FamilyTreeNodeType::TWNT_FAMILY_ROOT);

    return pFamilyRoot;
}

void gfam::FamilyBlock::refresh(gcmp::IUiDocument* pUiDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_parentNodeDelegate, L"m_parentNodeDelegate为空", L"paramodel", L"2024-02-20");
    TreeNode* pParentNode = m_parentNodeDelegate->getDelegatedNode();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParentNode != nullptr, L"pParentNode为空", L"paramodel", L"2024-02-20");

    if (FamilyCmdAvailibilityUtils::IsInProfileEditMode())
    {
        pParentNode->setEnable(false);
        return;
    }
    else
    {
        pParentNode->setEnable(true);
    }

    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDoc != nullptr, L"pUiDoc is nullptr", L"paramodel", L"2024-02-20");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pDoc指针为空", L"paramodel", L"2024-02-20");
    DBG_WARN_AND_RETURN_VOID_UNLESS(ICategoryLibrary::Get(pDoc) != nullptr, L"ICategoryLibrary::Get(pDoc)指针为空", L"paramodel", L"2024-02-20");

    std::vector<IFamily*> pFamilies = IFamily::GetAllFamilies(pDoc);

    //添加族节点
    FOR_EACH(pFamily, pFamilies)
    {
        DBG_WARN_AND_CONTINUE_UNLESS(pFamily->GetBasicInformation() != nullptr, L"GetBasicInformation()指针为空", L"paramodel", L"2024-02-20");
        const ICategory* pCategory = ICategoryLibrary::Get(pDoc)->GetCategory(pFamily->GetBasicInformation()->GetCategoryUid());
        DBG_WARN_AND_CONTINUE_UNLESS(pCategory, L"pCategory为空", L"paramodel", L"2024-02-20");

        bool existed = false;
        ExplorerTreeNodeDelegate* pCategoryItemDelegate = m_parentNodeDelegate->addSubNode(pCategory->GetName(), existed);
        DBG_WARN_AND_CONTINUE_UNLESS(pCategoryItemDelegate, L"pCategoryItemDelegate is nullptr", L"paramodel", L"2024-02-20");

        TreeNode* pCategoryItem = pCategoryItemDelegate->getDelegatedNode();
        DBG_WARN_AND_CONTINUE_UNLESS(pCategoryItem, L"pCategoryItem is nullptr", L"paramodel", L"2024-02-20");

        if (!existed)
        {
            std::wstring categoryName = pCategory->GetName();
            pCategoryItem->setInfo(0, Info(categoryName, categoryName, GnufFamilyTreeNodeUtil::GetIconPathByFamilyCategoryName(categoryName)));
            pCategoryItem->setUserDataAt(Gnuf_FAMILY_USER_DATA_ROLE, FamilyTreeNodeType::TWNT_FAMILY_CATEGORY);
        }
        pCategoryItem->setVisible(true);

        existed = false;
        ExplorerTreeNodeDelegate* pFamilyItemDelegate = pCategoryItemDelegate->addSubNode(pFamily->GetBasicInformation()->GetName(), existed);
        DBG_WARN_AND_CONTINUE_UNLESS(pFamilyItemDelegate, L"pFamilyItemDelegate is nullptr", L"paramodel", L"2024-02-20");

        TreeNode* pFamilyItem = pFamilyItemDelegate->getDelegatedNode();
        DBG_WARN_AND_CONTINUE_UNLESS(pFamilyItem, L"pFamilyItem is nullptr", L"paramodel", L"2024-02-20");

        if (!existed)
        {
            std::wstring familyName = pFamily->GetBasicInformation()->GetName();
            pFamilyItem->setInfo(0, Info(familyName, familyName, GnufFamilyTreeNodeUtil::GetIconPathByFamilyName(familyName)));
            pFamilyItem->setUserDataAt(Gnuf_FAMILY_USER_DATA_ROLE, FamilyTreeNodeType::TWNT_FAMILY);
        }

        //添加族类型节点
        auto familyTypes = pFamily->GetFamilyTypes();
        FOR_EACH(familyType, familyTypes)
        {
            existed = false;
            ExplorerTreeNodeDelegate* pFamilyTypeItemDelegate = pFamilyItemDelegate->addSubNode(familyType->GetName(), existed);
            DBG_WARN_AND_CONTINUE_UNLESS(pFamilyTypeItemDelegate, L"pFamilyTypeItemDelegate is nullptr", L"paramodel", L"2024-02-20");

            TreeNode* pFamilyTypeItem = pFamilyTypeItemDelegate->getDelegatedNode();
            DBG_WARN_AND_CONTINUE_UNLESS(pFamilyTypeItem, L"pFamilyTypeItem is nullptr", L"paramodel", L"2024-02-20");

            if (!existed)
            {
                pFamilyTypeItem->setUserDataAt(Gnuf_FAMILY_USER_DATA_ROLE, FamilyTreeNodeType::TWNT_FAMILYTYPE);
                pFamilyTypeItem->setInfo(0, Info(familyType->GetName(), familyType->GetName(), GnufFamilyTreeNodeUtil::GetIconPathByFamilyTypeName(familyType->GetName())));
            }
        }
    }

    if (m_parentNodeDelegate->getDelegatedNode())
    {
        m_parentNodeDelegate->getDelegatedNode()->sort(true);
    }
}

gnuf::TreeNode* gfam::ImportedObjectBlock::initBlockImpl(gnuf::TreeBoard* treeBoard, const std::vector<gcmp::Any>& datas)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(treeBoard, L"treeBoard is nullptr", L"paramodel", L"2024-02-20");
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(datas.size() == 1, L"the size of custom data should be 1", L"paramodel", L"2024-02-20");

    TreeNode* pNewNode = treeBoard->addTree();
    pNewNode->setInfo(0, Info(getBlockName(), getBlockName(), GnufFamilyTreeNodeUtil::GetIconPathForImportedObject()));
    pNewNode->setUserDataAt(Gnuf_FAMILY_USER_DATA_ROLE, datas[0]);

    return pNewNode;
}

void gfam::ImportedObjectBlock::refresh(gcmp::IUiDocument* pUiDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDoc != nullptr, L"pUiDoc is nullptr", L"paramodel", L"2024-02-20");
    DBG_WARN_AND_RETURN_VOID_UNLESS(m_parentNodeDelegate, L"m_parentNodeDelegate为空", L"paramodel", L"2024-02-20");

    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pDoc指针为空", L"paramodel", L"2024-02-20");

    // SAT 节点
    std::map<std::wstring, IElement*> satSheetsToBeAdded;
    // CAD图纸 节点
    std::map<std::wstring, IElement*> cadSheetsToBeAdded;
    FOR_EACH(pElement, m_source)
    {
        IGenericElement*pGenericElement = quick_cast<IGenericElement>(pElement);
        if (pGenericElement)
        {
            IFamilyExternalForm* pFamilyExternalForm = quick_cast<IFamilyExternalForm>(pGenericElement->GetExternalObject());
            if (pFamilyExternalForm)
            {
                if (pFamilyExternalForm->GetOwnerElement() 
                    && pFamilyExternalForm->GetOwnerElement()->GetBasicInformation()
                    && IsCADSheet(pFamilyExternalForm->GetOwnerElement()->GetBasicInformation()->GetName()))
                {
                    satSheetsToBeAdded.insert(std::make_pair(pFamilyExternalForm->GetOwnerElement()->GetBasicInformation()->GetName(), pElement));
                }

                continue;
            }
        }

        IElementBasicInformation* pElementBasicInfo = pElement->GetBasicInformation();
        DBG_WARN_AND_CONTINUE_UNLESS(pElementBasicInfo, L"pElementBasicInfo为空", L"paramodel", L"2024-02-20");

        if (IsCADSheet(pElementBasicInfo->GetName()))
            cadSheetsToBeAdded.insert(std::make_pair(pElementBasicInfo->GetName(), pElement));
    }

    DBG_WARN_AND_RETURN_VOID_UNLESS(m_parentNodeDelegate != nullptr, L"m_parentNodeDelegate指针为空", L"paramodel", L"2024-02-20");

    bool existed = false;
    ExplorerTreeNodeDelegate* pCADSheetCategoryDelegate = nullptr;
    TreeNode* pCADSheetCategory = nullptr;
    if (!cadSheetsToBeAdded.empty())
    {
        pCADSheetCategoryDelegate = m_parentNodeDelegate->addSubNode(CAD_SHEET_CATEGORY_TEXT, existed);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pCADSheetCategoryDelegate, L"pCADSheetCategoryDelegate is nullptr", L"paramodel", L"2024-02-20");

        pCADSheetCategory = pCADSheetCategoryDelegate->getDelegatedNode();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pCADSheetCategory, L"pCADSheetCategory is nullptr", L"paramodel", L"2024-02-20");

        if (!existed)
        {
            pCADSheetCategory->setInfo(0, Info(CAD_SHEET_CATEGORY_TEXT, CAD_SHEET_CATEGORY_TEXT, GnufFamilyTreeNodeUtil::GetIconPathForCADSheetCategory()));
            pCADSheetCategory->setUserDataAt(Gnuf_FAMILY_USER_DATA_ROLE, FamilyTreeNodeType::TWNT_CAD_SHEET_CATEGORY);
        }

        // 把不在树里的节点加上去
        for (auto itr = cadSheetsToBeAdded.begin(); itr != cadSheetsToBeAdded.end(); ++itr)
        {
            if (!itr->second)
            {
                continue;
            }

            if (!itr->second->GetBasicInformation())
            {
                continue;
            }

            std::wstring strName = itr->second->GetBasicInformation()->GetName();
            bool existed = false;
            ExplorerTreeNodeDelegate* pCADSheetDelegate = pCADSheetCategoryDelegate->addSubNode(strName, existed);
            DBG_WARN_AND_RETURN_VOID_UNLESS(pCADSheetDelegate, L"pCADSheetDelegate is nullptr", L"paramodel", L"2024-02-20");

            TreeNode* pCADSheet = pCADSheetDelegate->getDelegatedNode();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pCADSheet, L"pCADSheet is nullptr", L"paramodel", L"2024-02-20");

            if (!existed)
            {
                pCADSheet->setInfo(0, Info(strName, strName, GnufFamilyTreeNodeUtil::GetIconPathForCADSheet()));
                pCADSheet->setUserDataAt(Gnuf_FAMILY_USER_DATA_ROLE, FamilyTreeNodeType::TWNT_CAD_SHEET);
                {
                    IElement* pElement = itr->second;
                    // 把FamilyType信息加进去，在插入族实例时需要该信息。
                    IFamily* pFamily = quick_cast<IFamily>(pElement);
                    if (pFamily)
                    {
                        const std::vector<const IFamilyType*> familyTypes = pFamily->GetFamilyTypes();
                        DBG_WARN_AND_CONTINUE_UNLESS(familyTypes.size() == 1, L"DXF导入对象的FamilyType只有一个", L"paramodel", L"2024-02-20");
                        std::wstring familyTypeName = familyTypes[0]->GetName();
                        pCADSheet->setUserDataAt(Gnuf_CAD_SHEET_ITEM_FAMILY_TYPE, familyTypeName);
                    }
                }
                pCADSheetCategory->setExpanded(true);
            }
        }

        pCADSheetCategory->sort(true);
    }

    bool isSatExisted = false;
    ExplorerTreeNodeDelegate* pSATSheetCategoryDelegate = nullptr;
    TreeNode* pSATSheetCategory = nullptr;
    if (!satSheetsToBeAdded.empty())
    {
        pSATSheetCategoryDelegate = m_parentNodeDelegate->addSubNode(SAT_SHEET_CATEGORY_TEXT, isSatExisted);
        DBG_WARN_AND_RETURN_VOID_UNLESS(pSATSheetCategoryDelegate, L"pSATSheetCategoryDelegate is nullptr", L"paramodel", L"2024-02-20");

        pSATSheetCategory = pSATSheetCategoryDelegate->getDelegatedNode();
        DBG_WARN_AND_RETURN_VOID_UNLESS(pSATSheetCategory, L"pSATSheetCategory is nullptr", L"paramodel", L"2024-02-20");

        if (!isSatExisted)
        {
            pSATSheetCategory->setInfo(0, Info(SAT_SHEET_CATEGORY_TEXT, SAT_SHEET_CATEGORY_TEXT, GnufFamilyTreeNodeUtil::GetIconPathForCADSheetCategory()));
            pSATSheetCategory->setUserDataAt(Gnuf_FAMILY_USER_DATA_ROLE, FamilyTreeNodeType::TWNT_CAD_SHEET_CATEGORY);
        }

        for (auto itr = satSheetsToBeAdded.begin(); itr != satSheetsToBeAdded.end(); ++itr)
        {
            std::wstring strName = itr->second->GetBasicInformation()->GetName();
            bool existed = false;
            ExplorerTreeNodeDelegate* pSATSheetDelegate = pSATSheetCategoryDelegate->addSubNode(strName, existed);
            DBG_WARN_AND_RETURN_VOID_UNLESS(pSATSheetDelegate, L"pSATSheetDelegate is nullptr", L"paramodel", L"2024-02-20");

            TreeNode* pSATSheet = pSATSheetDelegate->getDelegatedNode();
            DBG_WARN_AND_RETURN_VOID_UNLESS(pSATSheet, L"pSATSheet is nullptr", L"paramodel", L"2024-02-20");

            if (!existed)
            {
                pSATSheet->setInfo(0, Info(strName, strName, GnufFamilyTreeNodeUtil::GetIconPathForCADSheet()));
                pSATSheet->setUserDataAt(Gnuf_FAMILY_USER_DATA_ROLE, FamilyTreeNodeType::TWNT_CAD_SHEET);
                {
                    IElement* pElement = itr->second;
                    // 把FamilyType信息加进去，在插入族实例时需要该信息。
                    IFamily* pFamily = quick_cast<IFamily>(pElement);
                    if (pFamily)
                    {
                        const std::vector<const IFamilyType*> familyTypes = pFamily->GetFamilyTypes();
                        DBG_WARN_AND_CONTINUE_UNLESS(familyTypes.size() == 1, L"SAT导入对象的FamilyType只有一个", L"paramodel", L"2024-02-20");
                        std::wstring familyTypeName = familyTypes[0]->GetName();
                        pSATSheet->setUserDataAt(Gnuf_CAD_SHEET_ITEM_FAMILY_TYPE, familyTypeName);
                    }
                }
                pSATSheetCategory->setExpanded(true);
            }
        }

        pSATSheetCategory->sort(true);
    }

}

void gfam::ImportedObjectDynamicArea::refreshArea(gcmp::IUiDocument* pUiDoc)
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDoc != nullptr, L"pUiDoc is nullptr", L"paramodel", L"2024-02-20");

    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc != nullptr, L"pDoc is nullptr", L"paramodel", L"2024-02-20");

    std::vector<IElement*> importedObjects = pDoc->GetElementsByCategory(BuiltInCategoryUniIdentities::BICU_IMPORTED_CAD_OBJECT, nullptr);

    std::vector<IElement*> forms = pDoc->GetElementsByCategory(BuiltInCategoryUniIdentities::BICU_FORM, nullptr);
    if (!forms.empty())
    {
        FOR_EACH(form, forms)
        {
            IGenericElement*pGenericElement = quick_cast<IGenericElement>(form);
            if (pGenericElement)
            {
                IFamilyExternalForm* pFamilyExternalForm = quick_cast<IFamilyExternalForm>(pGenericElement->GetExternalObject());
                if (pFamilyExternalForm)
                {
                    importedObjects.emplace_back(form);
                }
            }
        }
    }
    if (importedObjects.empty())
        return;

    DynamicExplorerBlock* dynamicBlock = addOrGetDynamicBlock<ImportedObjectBlock>(IMPORTED_OBJ_TEXT, { FamilyTreeNodeType::TWNT_IMPORTED_OBJECT_ROOT });
    if (dynamicBlock)
    {
        FOR_EACH(object, importedObjects)
        {
            if (object)
            {
                dynamicBlock->addSource(object);
            }
        }
    }
}

REGISTER_DYNAMIC_EXPLORER_AREA(ImportedObjectDynamicArea);
